using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections.Generic;

namespace OA.Common
{
    public static class ObjectUtils
    {

        #region 复制
        /// <summary>
        /// 复制一个对象，并返回复制的新对象
        /// </summary>
        /// <returns>复制的新对象
        /// object.</returns>
        public static T Clone<T>(object src) where T:new()
        {
            //First we create an instance of src specific type.
            T newObject = new T();
            Copy(src, newObject, true);
            return newObject;
        }

        /// <summary>
        /// 复制一个对象，并返回复制的新对象
        /// </summary>
        /// <returns>复制的新对象
        /// object.</returns>
        public static object Clone(object src)
        {
            //First we create an instance of src specific type.
            object newObject = Activator.CreateInstance(src.GetType());
            Copy(src, newObject, true);
            return newObject;
        }

        /// <summary>
        /// 将一个对象的属性复制到另一个对象
        /// </summary>
        /// <param name="src">源对象</param>
        /// <param name="target">目标对象</param>
        /// <param name="isDepth">是否执行深度复制</param>
        public static void Copy(object src, object target, bool isDepth)
        {
            if(src==null || target==null)
            {
                target = null;
                return;
            }
            #region 复制字段
            var fields = target.GetType().GetFields();
            foreach (FieldInfo fi in src.GetType().GetFields())
            {
                var field = fields.FirstOrDefault(r => r.Name == fi.Name);
                if (field != null)
                {
                    object srcValue = fi.GetValue(src);
                    object targetValue = srcValue;
                    if (isDepth && srcValue != null)  //深度复制
                    {
                        #region 深度复制
                        Type ICloneType = fi.FieldType.GetInterface("ICloneable", true);
                        if (ICloneType != null)   //属性是否自带深度复制
                        {
                            ICloneable IClone = (ICloneable)srcValue;
                            targetValue = IClone.Clone();
                        }
                        else if (field.FieldType.IsClass && field.FieldType.GetConstructors().Length > 0)
                        {
                            targetValue = Activator.CreateInstance(field.FieldType);
                            Copy(srcValue, targetValue, isDepth);
                            Type IEnumerableType = field.FieldType.GetInterface("IEnumerable", true);
                            if (IEnumerableType != null)
                            {
                                Type IListType = field.FieldType.GetInterface("IList", true);
                                if (IListType != null)
                                {
                                    int j = 0;
                                    IList list = (IList)targetValue;
                                    IEnumerable IEnum = (IEnumerable)srcValue;
                                    foreach (object obj in IEnum)
                                    {
                                        ICloneType = obj.GetType().GetInterface("ICloneable", true);
                                        if (ICloneType != null)
                                        {
                                            ICloneable clone = (ICloneable)obj;
                                            list.Add(clone.Clone());
                                        }
                                        else
                                        {
                                            object newlistitem = Activator.CreateInstance(obj.GetType());
                                            Copy(obj, newlistitem, isDepth);
                                            list.Add(newlistitem);
                                        }
                                        j++;
                                    }
                                }
                                else
                                {
                                    Type IDicType = field.FieldType.GetInterface("IDictionary", true);
                                    if (IDicType != null)
                                    {

                                        int j = 0;
                                        IDictionary dic = (IDictionary)targetValue;
                                        IEnumerable IEnum = (IEnumerable)srcValue;
                                        foreach (DictionaryEntry de in IEnum)
                                        {
                                            ICloneType = de.Value.GetType().GetInterface("ICloneable", true);
                                            if (ICloneType != null)
                                            {
                                                ICloneable clone = (ICloneable)de.Value;
                                                dic[de.Key] = clone.Clone();
                                            }
                                            else
                                            {
                                                Copy(de, dic[de.Key], isDepth);
                                            }
                                            j++;
                                        }
                                    }
                                }
                            }
                        }
                        #endregion
                    }
                    field.SetValue(target, targetValue);
                }
            }
            #endregion

            #region 复制属性
            var propers = target.GetType().GetProperties();
            foreach (PropertyInfo fi in src.GetType().GetProperties())
            {
                var proper = propers.FirstOrDefault(r => r.Name == fi.Name);
                if (proper != null && proper.CanWrite && fi.CanRead && fi.GetAccessors()[0].GetParameters().Length == 0)
                {
                    object srcValue = fi.GetValue(src, null);
                    object targetValue = srcValue;
                    if (isDepth && srcValue != null)  //深度复制
                    {
                        #region 深度复制
                        Type ICloneType = fi.PropertyType.GetInterface("ICloneable", true);
                        if (ICloneType != null)   //属性是否自带深度复制
                        {
                            ICloneable IClone = (ICloneable)srcValue;
                            targetValue = IClone.Clone();
                        }
                        else if (proper.PropertyType.IsClass && proper.PropertyType.GetConstructors().Length > 0)
                        {
                            targetValue = Activator.CreateInstance(proper.PropertyType);
                            Copy(srcValue, targetValue, isDepth);
                            Type IEnumerableType = proper.PropertyType.GetInterface("IEnumerable", true);
                            if (IEnumerableType != null)
                            {
                                Type IListType = proper.PropertyType.GetInterface("IList", true);
                                if (IListType != null)
                                {
                                    int j = 0;
                                    IList list = (IList)targetValue;
                                    IEnumerable IEnum = (IEnumerable)srcValue;
                                    foreach (object obj in IEnum)
                                    {
                                        ICloneType = obj.GetType().GetInterface("ICloneable", true);
                                        if (ICloneType != null)
                                        {
                                            ICloneable clone = (ICloneable)obj;
                                            list.Add(clone.Clone());
                                        }
                                        else
                                        {
                                            object newlistitem = Activator.CreateInstance(obj.GetType());
                                            Copy(obj, newlistitem, isDepth);
                                            list.Add(newlistitem);
                                        }
                                        j++;
                                    }
                                }
                                else
                                {
                                    Type IDicType = proper.PropertyType.GetInterface("IDictionary", true);
                                    if (IDicType != null)
                                    {

                                        int j = 0;
                                        IDictionary dic = (IDictionary)targetValue;
                                        IEnumerable IEnum = (IEnumerable)srcValue;
                                        foreach (DictionaryEntry de in IEnum)
                                        {
                                            ICloneType = de.Value.GetType().GetInterface("ICloneable", true);
                                            if (ICloneType != null)
                                            {
                                                ICloneable clone = (ICloneable)de.Value;
                                                dic[de.Key] = clone.Clone();
                                            }
                                            else
                                            {
                                                Copy(de, dic[de.Key], isDepth);
                                            }
                                            j++;
                                        }
                                    }
                                }
                            }
                        }
                        #endregion
                    }
                    proper.SetValue(target, targetValue, null);
                }
            }
            #endregion
        }

        #endregion

        #region 设置属性值

        /// <summary>
        /// 设置模型的属性值
        /// </summary>
        /// <param name="obj">模型</param>
        /// <param name="property">字段名称</param>
        /// <param name="value">值</param>
        public static bool SetPropertyValue(object obj,string property, object value)
        {
            bool ret = true;
            var type = obj.GetType();
            var propertys = property.Split('.');
            PropertyInfo propertyType = null;
            for (int i = 0; i < propertys.Length; i++)
            {
                propertyType = type.GetProperty(propertys[i]);
                if (propertyType == null) break;
                type = propertyType.PropertyType;
                if (i < propertys.Length - 1)
                {
                    obj = propertyType.GetValue(obj, null);
                }
            }
            if (propertyType!=null && value != null && type != value.GetType())
            {
                value = ConvertTo(value, type);
                if (value == null) ret = false;
            }
            if (ret) propertyType.SetValue(obj, value, null);
            return ret;
        }

        /// <summary>
        /// 设置模型的字段值
        /// </summary>
        /// <param name="obj">模型</param>
        /// <param name="property">字段名称</param>
        /// <param name="value">值</param>
        public static bool SetFieldValue(object obj, string field, object value)
        {
            bool ret = true;
            var type = obj.GetType();
            var fields = field.Split('.');
            FieldInfo fieldType = null;
            for (int i = 0; i < fields.Length; i++)
            {
                fieldType = type.GetField(fields[i]);
                if (fieldType == null) break;
                type = fieldType.FieldType;
                if (i < fields.Length - 1)
                {
                    obj = fieldType.GetValue(obj);
                }
            }
            if (fieldType != null && value != null && type != value.GetType())
            {
                value = ConvertTo(value, type);
                if (value == null) ret = false;
            }
            if (ret) fieldType.SetValue(obj, value);
            return ret;
        }
        #endregion

        #region 获取属性值
        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="propertyName">属性全称</param>
        /// <returns></returns>
        public static object GetPropertyValue(object obj, string propertyName)
        {
            object ret = obj;
            var type = obj.GetType();
            var propertys = propertyName.Split('.');
            for (int i = 0; i < propertys.Length; i++)
            {
                var pro = type.GetProperty(propertys[i]);
                if (pro != null)
                {
                    ret = pro.GetValue(ret, null);
                    if (ret == null) break;
                    type = pro.PropertyType;
                }
                else
                {
                    ret = null;
                    break;
                }
            }
            return ret;
        }

        public static object GetFieldValue(object obj, string fieldName)
        {
            object ret = obj;
            var type = obj.GetType();
            var fileds = fieldName.Split('.');
            for (int i = 0; i < fileds.Length; i++)
            {
                var pro = type.GetField(fileds[i]);
                if (pro != null)
                {
                    ret = pro.GetValue(ret);
                    if (ret == null) break;
                    type = pro.FieldType;
                }
                else
                {
                    ret = null;
                    break;
                }
            }
            return ret;
        }
        #endregion

        /// <summary>
        /// 转换类型
        /// </summary>
        /// <param name="value">要转换的对象</param>
        /// <param name="descType">转换的类型</param>
        public static object ConvertTo(object value, Type type)
        {
            if (value != null && type != value.GetType())
            {
                bool isNullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);  //是否是Nullable
                if (isNullable)
                {
                    type = type.GetGenericArguments()[0];
                }
                if (type != value.GetType())
                {
                    var convert = System.ComponentModel.TypeDescriptor.GetConverter(type);
                    if (convert != null)
                    {
                        try
                        {
                            value = convert.ConvertFrom(value);
                        }
                        catch  //转换失败时
                        {
                            try
                            {
                                value = value.ToString();
                                value = convert.ConvertFrom(value);
                            }
                            catch
                            {
                                if (isNullable) value = null;
                            }
                        }
                    }
                }
            }
            return value;
        }

    }
}
